﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Collections;

namespace SpeakerRecognition
{
    /// <summary>
    /// This Class is for saving configuration
    /// </summary>
    class xmlHandler
    {
        public static void saveFile(LogicLayerManager logicManager, string saveFileName)
        {
            createNewXmlSaveFile(saveFileName, "SPEAKER_RECOGNITION_USING_MFCC_SAVE_FILE" , logicManager); //create the save file

        }

        /// <summary>
        /// This method creates a NewXml Save File
        /// </summary>
        /// <param name="filepath">filePath(filename) to be saved</param>
        /// <param name="xmlRootElementId">root elemnts name</param>
        private static void createNewXmlSaveFile(String filepath, String xmlRootElementId , LogicLayerManager logicMan)
        {
            XmlTextWriter xtw;  //create instance for xmltextwriter. Xml Text Writer
            xtw = new XmlTextWriter(filepath, Encoding.UTF8);//assign  file path and encoding
            xtw.WriteStartDocument(); //write start document
            xtw.WriteStartElement(xmlRootElementId); //create root element
            xtw.WriteEndElement(); //end root element
            xtw.Close(); //close file. It is automatically saved.
            //ADD THE ELEMENTS FOR SAVING DATA
            XmlDocument xd = new XmlDocument();     //object creation for XmlDocument class
            FileStream lfile = new FileStream(filepath, FileMode.Open); //open an xml file using file stream
            xd.Load(lfile); //load opened file in xml document
            
            //Add FileList Node
            XmlElement cl = xd.CreateElement("FILES_IN_PROCESS"); //create an xml element 
            cl.InnerText = stringArrayAsCommaSeperatedString(logicMan.InputFiles);      
            xd.DocumentElement.AppendChild(cl); //append root element to xml document

            cl = xd.CreateElement("FILES_NAMES_ONLY_IN_PROCESS"); //create an xml element 
            cl.InnerText = stringArrayAsCommaSeperatedString(logicMan.InputFilesNamesOnly);
            xd.DocumentElement.AppendChild(cl); //append root element to xml document

            cl = xd.CreateElement("PAM_INPUT_MFCCS"); //create an xml element 
            cl.InnerText = pamInputdataAsString(logicMan.InputMFCCDataToPAM);
            xd.DocumentElement.AppendChild(cl); //append root element to xml document         

            cl = xd.CreateElement("ALPHA"); //create an xml element                      
            cl.InnerText = ""+logicMan.Alpha;
            xd.DocumentElement.AppendChild(cl); //append root element to xml document

            cl = xd.CreateElement("WINSIZE"); //create an xml element
            cl.InnerText = "" + logicMan.WinSize;
            xd.DocumentElement.AppendChild(cl); //append root element to xml document

            cl = xd.CreateElement("USING_HAMMING"); //create an xml element
            cl.InnerText = "" + logicMan.UsingHamming;
            xd.DocumentElement.AppendChild(cl); //append root element to xml document

            cl = xd.CreateElement("USE_STRIP_SILENCE"); //create an xml element
            cl.InnerText = "" + logicMan.UseStripSilence;
            xd.DocumentElement.AppendChild(cl); //append root element to xml document

            cl = xd.CreateElement("USE_REAL_ONLY"); //create an xml element
            cl.InnerText = "" + logicMan.RealOnly;
            xd.DocumentElement.AppendChild(cl); //append root element to xml document
   
            cl = xd.CreateElement("USE_FIRST_COEFF_AC"); //create an xml element
            cl.InnerText = "" + logicMan.UseFirstCoeffAC;
            xd.DocumentElement.AppendChild(cl); //append root element to xml document

            cl = xd.CreateElement("GET_HIGH_FREQ"); //create an xml element
            cl.InnerText = "" + logicMan.GetHighFreq;
            xd.DocumentElement.AppendChild(cl); //append root element to xml document

            cl = xd.CreateElement("OVERLAP"); //create an xml element
            cl.InnerText = "" + logicMan.OverLap;
            xd.DocumentElement.AppendChild(cl); //append root element to xml document

            cl = xd.CreateElement("POW_MAGNITUDE"); //create an xml element
            cl.InnerText = "" + logicMan.PowMagnitude;
            xd.DocumentElement.AppendChild(cl); //append root element to xml document
            
            cl = xd.CreateElement("NUMBER_OF_MFCC"); //create an xml element
            cl.InnerText = "" + logicMan.NumberOfMFCC;
            xd.DocumentElement.AppendChild(cl); //append root element to xml document
            
            cl = xd.CreateElement("USING_MEL_FILTER"); //create an xml element
            cl.InnerText = "" + logicMan.UsingMelFilter;
            xd.DocumentElement.AppendChild(cl); //append root element to xml document
            
            cl = xd.CreateElement("NUMBER_OF_CLUSTERS"); //create an xml element
            cl.InnerText = "" + logicMan.NumberOfClusters;
            xd.DocumentElement.AppendChild(cl); //append root element to xml document
                        
            cl = xd.CreateElement("WINDOW_TYPE"); //create an xml element
            cl.InnerText = "" + logicMan.WindowType;
            xd.DocumentElement.AppendChild(cl); //append root element to xml document

            cl = xd.CreateElement("DISTANCE_TYPE"); //create an xml element
            cl.InnerText = "" + Enum.GetName(typeof(DistanceMeasurement), logicMan.DistanceType);
            xd.DocumentElement.AppendChild(cl); //append root element to xml document
            
            lfile.Close(); //close the file stream
            xd.Save(filepath); //save the xmldocument content to the file
        }

        /// <summary>
        /// This method adds the alphaBet size used for the cretion of the filelist
        /// </summary>
        /// <param name="saveFilePath">The path of the saved file</param>
        /// <param name="AlphaBetSize">The alphaBet size as a String</param>
        private static void addFileListAlphaBetSizeToXmlDataBase(String saveFilePath,String AlphaBetSize)
        {

            XmlDocument xd = new XmlDocument();     //object creation for XmlDocument class
            FileStream lfile = new FileStream(saveFilePath, FileMode.Open); //open an xml file using file stream
            xd.Load(lfile); //load opened file in xml document
            XmlNode fileListNode = xd.GetElementsByTagName("FILE_LIST")[0]; //Files are added to the File List element in the XML document
            XmlElement fileElement = xd.CreateElement("FILE_LIST_ALPHA_BET_SIZE"); //create an xml element

            fileElement.InnerText = AlphaBetSize;
            fileListNode.AppendChild(fileElement);

            lfile.Close(); //close the file stream
            xd.Save(saveFilePath); //save the xmldocument content to the file
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private static String stringArrayAsCommaSeperatedString(String[] input)
        {
            String output = "";
            for (int i = 0; i < input.Length; i++)
                output += "," + input[i];
            output = output.Substring(1, output.Length - 1);
            return output;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private static String pamInputdataAsString(ArrayList input)
        {
            String output = "";
            for (int i = 0; i < input.Count; i++)
                output += "*" + doubleArrayAsString((double[])input[i]);
            output = output.Substring(1, output.Length - 1);
            return output;
        }
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private static String doubleArrayAsString(double[] input)
        {
            String output = "";
            for (int i = 0; i < input.Length; i++)
                output += "," + input[i];
            output = output.Substring(1, output.Length - 1);
            return output;
        }

        /// <summary>
        /// Convert comma seperated doubles string to an array of doubles
        /// </summary>
        /// <param name="doubleString">comma seperated doubles</param>
        /// <returns>an array of the double numbers</returns>
        private static double[] stringToDoubleArray(String doubleString)
        {
            String[] splited = doubleString.Split(',');
            double[] doubleArray = new double[splited.Length];
            for (int i = 0; i < doubleArray.Length; i++)
            {
                doubleArray[i] = double.Parse(splited[i]);
            }
            return doubleArray;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private static String[] comaSeperatedStringToArray(String input)
        {
            return  input.Split(',');
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private static ArrayList stringToPamInput(String input)
        {
            String[] splited = input.Split('*');
            ArrayList output = new ArrayList();
            for (int i=0; i<splited.Length; i++)
            {
                double[] mfcc= stringToDoubleArray((splited[i]));
                output.Add(mfcc);
            }
            return output;
        }

        /// <summary>
        /// This method appends a child node to an element
        /// </summary>
        /// <param name="xd">The xml document</param>
        /// <param name="Node">The node of the element we want to attach a child elemnt to</param>
        /// <param name="newChild">the child element to append</param>
        /// <param name="childsText">the childs element text</param>
        private static void appendChildToNode(XmlDocument xd, XmlNode Node, String newChild, String childsText)
        {
            XmlElement childElement = xd.CreateElement(newChild); //create an xml element
            XmlText childElementsText = xd.CreateTextNode(childsText); //create text for xml element
            childElement.AppendChild(childElementsText); //append address text to address node
            Node.AppendChild(childElement); //append address node to root element
        }

        /*******************************************************************************************************************************/   

        public static void loadFile(String filename , LogicLayerManager logiclayerManger)
        {
            XmlDocument xdoc = new XmlDocument(); //creation of XmlDocument class Instance
            FileStream rfile = new FileStream(filename, FileMode.Open); //create a file stream and open the file to be updated
            xdoc.Load(rfile);//load file into xmldocument instance
            XmlNodeList elemntList = xdoc.GetElementsByTagName("FILES_IN_PROCESS"); //find out the no of elements available in xml file   
            logiclayerManger.InputFiles = comaSeperatedStringToArray(elemntList[0].InnerText);

            elemntList = xdoc.GetElementsByTagName("FILES_NAMES_ONLY_IN_PROCESS"); //find out the no of elements available in xml file   
            logiclayerManger.InputFilesNamesOnly = comaSeperatedStringToArray(elemntList[0].InnerText);

            elemntList = xdoc.GetElementsByTagName("PAM_INPUT_MFCCS"); //find out the no of elements available in xml file   s
            logiclayerManger.InputMFCCDataToPAM = stringToPamInput(elemntList[0].InnerText);

            elemntList = xdoc.GetElementsByTagName("ALPHA"); //find out the no of elements available in xml file   
            logiclayerManger.Alpha = Double.Parse(elemntList[0].InnerText);

            elemntList = xdoc.GetElementsByTagName("WINSIZE"); //find out the no of elements available in xml file   
            logiclayerManger.WinSize = Int16.Parse(elemntList[0].InnerText);

            elemntList = xdoc.GetElementsByTagName("USING_HAMMING"); //find out the no of elements available in xml file   
            logiclayerManger.UsingHamming = Boolean.Parse(elemntList[0].InnerText);

            elemntList = xdoc.GetElementsByTagName("USE_STRIP_SILENCE"); //find out the no of elements available in xml file   
            logiclayerManger.UseStripSilence = Boolean.Parse(elemntList[0].InnerText);

            elemntList = xdoc.GetElementsByTagName("USE_REAL_ONLY"); //find out the no of elements available in xml file   
            logiclayerManger.RealOnly = Boolean.Parse(elemntList[0].InnerText);

            elemntList = xdoc.GetElementsByTagName("USE_FIRST_COEFF_AC"); //find out the no of elements available in xml file   
            logiclayerManger.UseFirstCoeffAC = Boolean.Parse(elemntList[0].InnerText);

            elemntList = xdoc.GetElementsByTagName("GET_HIGH_FREQ"); //find out the no of elements available in xml file   
            logiclayerManger.GetHighFreq = Boolean.Parse(elemntList[0].InnerText);

            elemntList = xdoc.GetElementsByTagName("OVERLAP"); //find out the no of elements available in xml file   
            logiclayerManger.OverLap = Int16.Parse(elemntList[0].InnerText);

            elemntList = xdoc.GetElementsByTagName("POW_MAGNITUDE"); //find out the no of elements available in xml file   
            logiclayerManger.PowMagnitude = Boolean.Parse(elemntList[0].InnerText);

            elemntList = xdoc.GetElementsByTagName("NUMBER_OF_MFCC"); //find out the no of elements available in xml file   
            logiclayerManger.NumberOfMFCC = Int16.Parse(elemntList[0].InnerText);

            elemntList = xdoc.GetElementsByTagName("USING_MEL_FILTER"); //find out the no of elements available in xml file   
            logiclayerManger.UsingMelFilter = Boolean.Parse(elemntList[0].InnerText);

            elemntList = xdoc.GetElementsByTagName("NUMBER_OF_CLUSTERS"); //find out the no of elements available in xml file   
            logiclayerManger.NumberOfClusters = Int16.Parse(elemntList[0].InnerText);

            elemntList = xdoc.GetElementsByTagName("WINDOW_TYPE"); //find out the no of elements available in xml file   
            logiclayerManger.WindowType = elemntList[0].InnerText;

            elemntList = xdoc.GetElementsByTagName("DISTANCE_TYPE"); //find out the no of elements available in xml file   
            logiclayerManger.DistanceType = (DistanceMeasurement)Enum.Parse(typeof (DistanceMeasurement),elemntList[0].InnerText);

            rfile.Close();
        }
    }
}
